from datetime import datetime
from langchain_community.vectorstores import Qdrant
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
from langchain_core.runnables import RunnableParallel, RunnablePassthrough
from langchain_community.embeddings import ZhipuAIEmbeddings
from langchain_community.chat_models import ChatZhipuAI
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain_community.document_loaders import PyPDFLoader
import gradio as gr
import os
import warnings

warnings.filterwarnings('ignore')

# 配置参数
ZHIPU_API_KEY = "2f39319bdd864fc4a41bf6b8eed6efbc.uIsAkRrMwejVTIyc"
INIT_FILE = '05_机器人工程设计专项赛.pdf'
CHUNK_SIZE = 1000
CHUNK_OVERLAP = 100

# 初始化核心组件
text_splitter = RecursiveCharacterTextSplitter(
    chunk_size=CHUNK_SIZE,
    chunk_overlap=CHUNK_OVERLAP
)
embeddings = ZhipuAIEmbeddings(api_key=ZHIPU_API_KEY)


# 初始化知识库
def init_knowledge_base():
    loader = PyPDFLoader(INIT_FILE)
    documents = loader.load()
    chunked_documents = text_splitter.split_documents(documents)

    return Qdrant.from_documents(
        documents=chunked_documents,
        embedding=embeddings,
        location=":memory:",
        collection_name="campus_qa"
    )


vectorstore = init_knowledge_base()
retriever = vectorstore.as_retriever()

# 构建问答链
template = """基于以下上下文回答问题：
{context}

问题：{question}
"""
prompt = ChatPromptTemplate.from_template(template)
model_zhipu = ChatZhipuAI(temperature=0.5, api_key=ZHIPU_API_KEY, model="glm-4")

chain = (
        RunnableParallel({"context": retriever, "question": RunnablePassthrough()})
        | prompt
        | model_zhipu
        | StrOutputParser()
)


# 文件处理功能
def process_uploaded_file(file):
    """处理上传的PDF文件"""
    try:
        loader = PyPDFLoader(file.name)
        new_docs = loader.load()
        chunks = text_splitter.split_documents(new_docs)

        vectorstore.add_documents(
            documents=chunks,
            embedding=embeddings
        )
        return f"✅ 成功新增 {len(chunks)} 个知识片段 | 更新时间：{datetime.now().strftime('%Y-%m-%d %H:%M')}"
    except Exception as e:
        return f"❌ 文件处理失败：{str(e)}"


# Gradio界面
def create_interface():
    with gr.Blocks(title="智慧校园智能问答系统", theme=gr.themes.Soft()) as interface:
        # 系统标题
        gr.Markdown("# 🎓 未来校园智能问答系统")

        # 知识库管理区
        with gr.Accordion("知识库管理", open=False):
            with gr.Row():
                file_upload = gr.File(label="上传PDF文档", file_types=[".pdf"])
                upload_btn = gr.Button("更新知识库", variant="primary")
            upload_status = gr.Textbox(label="操作日志", interactive=False)

        # 问答交互区
        with gr.Row():
            with gr.Column(scale=3):
                chat_history = gr.Chatbot(height=450, label="对话历史")
            with gr.Column(scale=2):
                question_input = gr.Textbox(
                    label="输入问题",
                    placeholder="请输入关于智能应用专项赛的问题...",
                    lines=5
                )
                submit_btn = gr.Button("提交提问", variant="primary")

        # 事件处理
        def respond(message, history):
            response = chain.invoke(message)
            history.append((message, response))
            return "", history

        # 绑定事件
        upload_btn.click(
            fn=process_uploaded_file,
            inputs=file_upload,
            outputs=upload_status
        )
        submit_btn.click(
            fn=respond,
            inputs=[question_input, chat_history],
            outputs=[question_input, chat_history]
        )

    return interface
import socket

def check_port(port):
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        return s.connect_ex(('localhost', port)) == 0

if check_port(7888):
    print("⚠️ 端口7888已被占用")
else:
    print("✅ 端口可用")

# 启动系统
if __name__ == "__main__":
    interface = create_interface()
    interface.launch(
        server_name="0.0.0.0",
        server_port=7888,  # 例如改为7070或8888
        share=True
    )